mod graphic_cell;
use graphic_cell::GraphicCell;

use std::{
    cmp::min,
    fmt::{self},
    ops::{Deref, Range},
};
use unicode_segmentation::UnicodeSegmentation;

use crate::{
    editor::highlighter::{AnnotatedStr, Annotation},
    prelude::*,
};

#[derive(Default, Clone)]
pub struct Line {
    cells: Vec<GraphicCell>,
    // 一行中所有图元构成的字符串
    string: String,
}

impl Line {
    pub fn from(str: &str) -> Self {
        Self {
            cells: Self::str_to_cells(str),
            string: String::from(str),
        }
    }

    // 将行字符串转为图形单元向量
    fn str_to_cells(str: &str) -> Vec<GraphicCell> {
        // 使用 fold 维护两个状态：当前终端列位置（current_col）、已生成的 GraphicCell 向量
        str.grapheme_indices(true)
            .fold(
                (0, Vec::new()),
                |(mut current_col, mut cells), (byte_idx, grapheme)| {
                    // 1. 调用 grapheme_to_cell，传入完整参数（grapheme + byte_idx(start) + current_col）
                    let cell = GraphicCell::grapheme_to_cell(grapheme, byte_idx, current_col);

                    // 2. 将生成的 cell 加入向量
                    cells.push(cell.clone()); // 克隆是为了后续获取宽度（也可先计算宽度再构造）

                    // 3. 更新 current_col：累加当前 cell 的渲染宽度
                    current_col += cell.rendering_width.to_usize();

                    // 4. 返回新的状态（更新后的 current_col + 向量）
                    (current_col, cells)
                },
            )
            .1 // fold 返回 (current_col, cells)，取第二个元素（向量）作为最终结果
    }

    fn rebuild_fragments(&mut self) {
        self.cells = Self::str_to_cells(&self.string);
    }

    pub fn get_visible_graphemes(&self, range: Range<ColIdx>) -> String {
        self.get_annotated_visible_substr(range, None).to_string()
    }

    pub fn get_annotated_visible_substr(
        &self,
        range: Range<ColIdx>,
        annotations: Option<&Vec<Annotation>>,
    ) -> AnnotatedStr {
        if range.start >= range.end {
            return AnnotatedStr::default();
        }

        let mut result = AnnotatedStr::from(&self.string);

        if let Some(annotations) = annotations {
            for annotation in annotations {
                result.add_annotation(annotation.annotation_type, annotation.start, annotation.end);
            }
        }

        let mut fragment_start = self.width();
        for cell in self.cells.iter().rev() {
            let fragment_end = fragment_start;
            fragment_start = fragment_start.saturating_sub(cell.rendering_width.to_usize());

            if fragment_start > range.end {
                continue;
            }
            if fragment_start < range.end && fragment_end > range.end {
                result.replace(cell.start, self.string.len(), "⋯");
                continue;
            } else if fragment_start == range.end {
                result.truncate_right_from(cell.start);
                continue;
            }

            if fragment_end <= range.start {
                result.truncate_left_until(cell.start.saturating_add(cell.content.len()));
                break;
            } else if fragment_start < range.start && fragment_end > range.start {
                result.replace(0, cell.start.saturating_add(cell.content.len()), "⋯");
                break;
            }

            if fragment_start >= range.start && fragment_end <= range.end {
                if let Some(ref replacement) = cell.replacement {
                    let start = cell.start;
                    let end = start.saturating_add(cell.content.len());
                    result.replace(start, end, &replacement);
                }
            }
        }

        result
    }

    // 获取当前行的图元的个数
    pub fn cells_count(&self) -> CellIdx {
        self.cells.len()
    }

    //  计算从行首到指定图元索引为止的所有图元的总终端列宽度
    pub fn width_until(&self, cell_idx: CellIdx) -> ColIdx {
        self.cells
            .iter()
            .take(cell_idx) // 截取前 `cell_idx` 个图元（只算到指定索引为止）
            .map(|cell| cell.rendering_width.to_usize())
            .sum()
    }

    pub fn width(&self) -> ColIdx {
        self.width_until(self.cells_count())
    }

    // 在某一行中的指定位置插入普通字符
    pub fn insert_char(&mut self, character: char, at: CellIdx) {
        debug_assert!(at.saturating_sub(1) <= self.cells_count());

        if let Some(fragment) = self.cells.get(at) {
            self.string.insert(fragment.start, character);
        } else {
            self.string.push(character);
        }
        self.rebuild_fragments();
    }

    pub fn append_char(&mut self, character: char) {
        self.insert_char(character, self.cells_count());
    }

    pub fn delete(&mut self, at: CellIdx) {
        debug_assert!(at <= self.cells_count());

        if let Some(fragment) = self.cells.get(at) {
            let start = fragment.start;
            let end = fragment.start.saturating_add(fragment.content.len());
            // 移除从起始位置到结束位置的子字符串。
            self.string.drain(start..end);
            self.rebuild_fragments();
        }
    }

    pub fn delete_last(&mut self) {
        self.delete(self.cells_count().saturating_sub(1));
    }

    pub fn append(&mut self, other: &Self) {
        self.string.push_str(&other.string);
        self.rebuild_fragments();
    }

    pub fn split(&mut self, at: CellIdx) -> Self {
        if let Some(fragment) = self.cells.get(at) {
            let remainder = self.string.split_off(fragment.start);
            self.rebuild_fragments();
            Self::from(&remainder)
        } else {
            Self::default()
        }
    }

    // 将给定的字节索引转换为图元索引
    fn byte_idx_to_grapheme_idx(&self, byte_idx: ByteIdx) -> Option<CellIdx> {
        if byte_idx > self.string.len() {
            return None;
        }

        self.cells
            .iter()
            .position(|fragment| fragment.start >= byte_idx)
    }

    // 将给定的图元索引转换为字节索引
    fn grapheme_idx_to_byte_idx(&self, grapheme_idx: CellIdx) -> ByteIdx {
        debug_assert!(grapheme_idx <= self.cells_count());

        if grapheme_idx == 0 || self.cells_count() == 0 {
            return 0;
        }

        self.cells.get(grapheme_idx).map_or_else(
            || {
                #[cfg(debug_assertions)]
                {
                    panic!("Fragment not found for grapheme index: {grapheme_idx:?}");
                }

                #[cfg(not(debug_assertions))]
                {
                    0
                }
            },
            |fragment| fragment.start,
        )
    }

    pub fn search_forward(&self, query: &str, from_grapheme_idx: CellIdx) -> Option<CellIdx> {
        debug_assert!(from_grapheme_idx <= self.cells_count());

        if from_grapheme_idx == self.cells_count() {
            return None;
        }

        let start = self.grapheme_idx_to_byte_idx(from_grapheme_idx);
        self.find_all(query, start..self.string.len())
            .first()
            .map(|(_, grapheme_idx)| *grapheme_idx)
    }

    pub fn search_backward(&self, query: &str, from_grapheme_idx: CellIdx) -> Option<CellIdx> {
        debug_assert!(from_grapheme_idx <= self.cells_count());

        if from_grapheme_idx == 0 {
            return None;
        }

        let end_byte_index = if from_grapheme_idx == self.cells_count() {
            self.string.len()
        } else {
            self.grapheme_idx_to_byte_idx(from_grapheme_idx)
        };

        self.find_all(query, 0..end_byte_index)
            .last()
            .map(|(_, grapheme_idx)| *grapheme_idx)
    }

    pub fn find_all(&self, query: &str, range: Range<ByteIdx>) -> Vec<(ByteIdx, CellIdx)> {
        let end = min(range.end, self.string.len());
        let start = range.start;

        debug_assert!(start <= end);
        debug_assert!(start <= self.string.len());

        self.string.get(start..end).map_or_else(Vec::new, |substr| {
            let potential_matches: Vec<ByteIdx> = substr
                .match_indices(query)
                .map(|(relative_start_idx, _)| relative_start_idx.saturating_add(start))
                .collect();

            self.match_grapheme_clusters(&potential_matches, query)
        })
    }

    fn match_grapheme_clusters(&self, matches: &[ByteIdx], query: &str) -> Vec<(ByteIdx, CellIdx)> {
        let grapheme_count = query.graphemes(true).count();

        matches
            .iter()
            .filter_map(|&start| {
                self.byte_idx_to_grapheme_idx(start)
                    .and_then(|grapheme_idx| {
                        self.cells
                            .get(grapheme_idx..grapheme_idx.saturating_add(grapheme_count))
                            .and_then(|fragments| {
                                let substring = fragments
                                    .iter()
                                    .map(|fragment| fragment.content.as_str())
                                    .collect::<String>();
                                (substring == query).then_some((start, grapheme_idx))
                            })
                    })
            })
            .collect()
    }
}

impl fmt::Display for Line {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.string)
    }
}

impl Deref for Line {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        &self.string
    }
}
